import tkinter as tk
from tkinter import ttk, messagebox
import pyperclip
import pandas as pd
from ttkbootstrap import Style
import threading
import re
import os
from datetime import datetime
from openpyxl import load_workbook
import queue


class IDSearchApp:
    def __init__(self, root):
        self.root = root
        self.root.title("身份证信息查询系统")
        self.root.geometry("500x450")

        # 设置窗口属性
        self.root.attributes('-toolwindow', True)
        self.root.attributes('-topmost', True)
        self.close_count = 0
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        # 初始化日志系统
        self.log_file = "id_search_log.txt"
        self.init_log_file()

        # 消息队列
        self.message_queue = queue.Queue()

        # 应用样式
        self.style = Style(theme='flatly')

        # 数据文件路径
        self.excel_path = self.get_latest_excel_file()

        # 初始化变量
        self.df = None
        self.data_loaded = False
        self.last_clipboard_content = ""
        self.current_id = ""
        self.wb = None
        self.ws = None
        self.id_column_idx = -1
        self.record_column_idx = -1

        # 创建界面
        self.create_widgets()

        # 加载数据
        self.load_data_thread()

        # 启动剪贴板监控
        self.start_clipboard_monitor()

        # 启动消息队列处理
        self.process_queue()

    def process_queue(self):
        try:
            while True:
                msg_type, *args = self.message_queue.get_nowait()
                if msg_type == "status":
                    self.status_var.set(args[0])
                elif msg_type == "log":
                    self.write_log(*args)
                elif msg_type == "error":
                    messagebox.showerror("错误", args[0])
                elif msg_type == "info":
                    if args and args[0] == "结果" and args[1] == "未找到匹配记录":
                        self.show_custom_messagebox(*args)
                    else:
                        messagebox.showinfo(*args)
        except queue.Empty:
            pass
        self.root.after(100, self.process_queue)

    def show_custom_messagebox(self, title, message):
        top = tk.Toplevel(self.root)
        top.title(title)
        top.geometry("300x100")

        # 计算居中位置
        window_width = 300
        window_height = 100
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        top.geometry(f"{window_width}x{window_height}+{x}+{y}")

        top.attributes('-topmost', True)

        label = ttk.Label(top, text=message)
        label.pack(pady=10)

        def on_ok():
            top.destroy()
            self.minimize_window()

        btn = ttk.Button(top, text="确定", command=on_ok, style='primary.TButton')
        btn.pack(pady=5)

    def on_close(self):
        self.close_count += 1
        if self.close_count == 1:
            self.reset_timer = self.root.after(2000, self.reset_close_count)

        remaining = 3 - self.close_count

        if self.close_count >= 3:
            if hasattr(self, 'reset_timer'):
                self.root.after_cancel(self.reset_timer)
            self.write_log("系统操作", "程序退出")
            self.clipboard_monitor_active = False
            self.root.destroy()
        else:
            self.status_var.set(f"再点击 {remaining} 次关闭按钮将退出程序")
            self.write_log("用户操作", f"尝试关闭程序 ({self.close_count}/3)")

    def reset_close_count(self):
        if self.close_count < 3:
            self.close_count = 0
            self.status_var.set("就绪")
            self.write_log("系统操作", "关闭计数器已重置")

    def init_log_file(self):
        if not os.path.exists(self.log_file):
            with open(self.log_file, "w", encoding="utf-8") as f:
                f.write("身份证查询系统日志\n")
                f.write("=" * 50 + "\n")

    def write_log(self, action, content, result=""):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {action}: {content}"
        if result:
            log_entry += f" | 结果: {result}"
        log_entry += "\n"

        with open(self.log_file, "a", encoding="utf-8") as f:
            f.write(log_entry)

        self.status_var.set(log_entry.strip())

    def create_widgets(self):
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 顶部标题和按钮
        header_frame = ttk.Frame(main_frame)
        header_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(
            header_frame,
            text="身份证信息查询系统",
            font=('Helvetica', 16, 'bold')
        ).pack(side=tk.LEFT)

        btn_frame = ttk.Frame(header_frame)
        btn_frame.pack(side=tk.RIGHT)

        close_btn = ttk.Button(
            btn_frame,
            text="关闭程序",
            command=self.on_close,
            style='danger.TButton',
            width=8,
            padding=(0, 0)
        )
        close_btn.pack(side=tk.RIGHT, padx=5)

        ttk.Button(
            btn_frame,
            text="查看日志",
            command=self.view_logs,
            style='info.Outline.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        # 搜索控制区
        control_frame = ttk.LabelFrame(
            main_frame,
            text="查询控制",
            padding=(15, 10)
        )
        control_frame.pack(fill=tk.X, pady=5)

        search_frame = ttk.Frame(control_frame)
        search_frame.pack(fill=tk.X, pady=5)

        ttk.Label(search_frame, text="身份证号:").pack(side=tk.LEFT)
        self.search_entry = ttk.Entry(search_frame, width=30)
        self.search_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        btn_frame = ttk.Frame(search_frame)
        btn_frame.pack(side=tk.LEFT, padx=5)

        ttk.Button(
            btn_frame,
            text="查询",
            command=self.search_id,
            style='success.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        ttk.Button(
            btn_frame,
            text="清空",
            command=self.clear_search,
            style='danger.TButton',
            width=8
        ).pack(side=tk.LEFT, padx=2)

        # 结果显示区
        result_frame = ttk.LabelFrame(
            main_frame,
            text="查询结果",
            padding=10
        )
        result_frame.pack(fill=tk.BOTH, expand=True)

        self.result_text = tk.Text(
            result_frame,
            wrap=tk.WORD,
            font=('Microsoft YaHei', 11),
            padx=10,
            pady=10,
            height=8,
            state=tk.DISABLED
        )
        self.result_text.pack(fill=tk.BOTH, expand=True)

        # 配置文本标签样式
        current_size = 12
        self.result_text.tag_config('header', font=('Microsoft YaHei', current_size * 2, 'bold'), foreground='red')

        # 底部按钮框架
        bottom_frame = ttk.Frame(main_frame)
        bottom_frame.pack(fill=tk.X, pady=(5, 0))

        self.follow_up_btn = ttk.Button(
            bottom_frame,
            text="新建随访",
            command=self.add_follow_up,
            style='primary.TButton',
            width=10,
            state=tk.DISABLED
        )
        self.follow_up_btn.pack(side=tk.RIGHT, padx=5)

        self.confirm_btn = ttk.Button(
            bottom_frame,
            text="关闭窗口",
            command=self.minimize_window,
            style='danger.TButton',
            width=8
        )
        self.confirm_btn.pack(side=tk.RIGHT, padx=5)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("系统就绪")
        status_bar = ttk.Label(
            main_frame,
            textvariable=self.status_var,
            relief=tk.SUNKEN,
            anchor=tk.W,
            padding=(10, 5, 10, 5),
            font=('Microsoft YaHei', 9),
            style='secondary.TLabel'
        )
        status_bar.pack(fill=tk.X, pady=(5, 0))

        self.search_entry.bind('<Return>', lambda e: self.search_id())

    def add_follow_up(self):
        if not self.current_id:
            return

        try:
            row_idx = self.df.index.get_loc(self.current_id)

            if pd.isna(self.df.at[self.current_id, "检查记录登记"]):
                today = datetime.now().strftime("%Y-%m-%d %H:%M")

                self.df.at[self.current_id, "检查记录登记"] = today

                excel_row = row_idx + 2
                self.ws.cell(row=excel_row, column=self.record_column_idx + 1, value=today)
                self.wb.save(self.excel_path)

                self.search_id()
                # 更新后禁用按钮
                self.follow_up_btn.config(state=tk.DISABLED, style='primary.TButton')

                self.message_queue.put(("info", "成功", f"已添加随访记录: {today}"))
                self.message_queue.put(
                    ("log", "随访记录", self.current_id[:6] + "..." + self.current_id[-4:], f"添加随访日期: {today}"))
            else:
                # 创建提示窗口
                top = tk.Toplevel(self.root)
                top.title("提示")
                top.geometry("300x100")

                # 计算居中位置
                window_width = 300
                window_height = 100
                screen_width = self.root.winfo_screenwidth()
                screen_height = self.root.winfo_screenheight()
                x = (screen_width - window_width) // 2
                y = (screen_height - window_height) // 2
                top.geometry(f"{window_width}x{window_height}+{x}+{y}")

                top.attributes('-topmost', True)

                label = ttk.Label(top, text="该身份证已有随访记录")
                label.pack(pady=10)

                def on_ok():
                    top.destroy()
                    self.minimize_window()  # 关闭主窗口

                btn = ttk.Button(top, text="确定", command=on_ok, style='primary.TButton')
                btn.pack(pady=5)

        except Exception as e:
            self.message_queue.put(("error", f"添加随访记录失败: {str(e)}"))
            self.message_queue.put(("log", "随访错误", self.current_id[:6] + "..." + self.current_id[-4:], str(e)))

    def minimize_window(self):
        self.root.withdraw()
        self.write_log("用户操作", "窗口隐藏")

    def restore_window(self):
        if not self.root.winfo_viewable():
            self.root.deiconify()
            self.root.attributes('-topmost', True)
            self.write_log("系统操作", "窗口已恢复")

    def view_logs(self):
        try:
            with open(self.log_file, "r", encoding="utf-8") as f:
                logs = f.read()

            log_window = tk.Toplevel(self.root)
            log_window.title("查询日志")
            log_window.geometry("800x600")
            log_window.attributes('-topmost', True)

            text_frame = ttk.Frame(log_window)
            text_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

            log_text = tk.Text(
                text_frame,
                wrap=tk.WORD,
                font=('Courier New', 10)
            )
            log_text.pack(fill=tk.BOTH, expand=True)
            log_text.insert(tk.END, logs)
            log_text.config(state=tk.DISABLED)

            btn_frame = ttk.Frame(log_window)
            btn_frame.pack(fill=tk.X, padx=10, pady=(0, 10))

            ttk.Button(
                btn_frame,
                text="关闭",
                command=log_window.destroy,
                style='danger.TButton'
            ).pack(side=tk.RIGHT)

        except Exception as e:
            self.message_queue.put(("error", f"无法读取日志文件: {str(e)}"))

    def start_clipboard_monitor(self):
        self.clipboard_monitor_active = True
        self.monitor_clipboard()

    def monitor_clipboard(self):
        if not hasattr(self, 'clipboard_monitor_active') or not self.clipboard_monitor_active:
            return

        try:
            current_content = pyperclip.paste().strip()

            if (current_content != self.last_clipboard_content and
                    self.is_valid_id_number(current_content)):
                self.restore_window()
                self.search_entry.delete(0, tk.END)
                self.search_entry.insert(0, current_content)
                self.write_log("剪贴板检测到身份证号", current_content[:6] + "..." + current_content[-4:])
                self.search_id()
                self.last_clipboard_content = current_content

        except Exception as e:
            print(f"剪贴板监控错误: {e}")

        self.root.after(300, self.monitor_clipboard)

    def get_latest_excel_file(self):
        current_dir = os.getcwd()
        xlsx_files = [f for f in os.listdir(current_dir) if f.endswith('.xlsx')]

        if xlsx_files:
            return os.path.join(current_dir, xlsx_files[0])
        else:
            raise FileNotFoundError("未找到任何 .xlsx 文件")

    def is_valid_id_number(self, text):
        pattern = r'^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$'
        return re.match(pattern, text) is not None

    def load_data_thread(self):
        self.message_queue.put(("status", "正在加载数据文件..."))
        self.message_queue.put(("log", "系统操作", "开始加载数据文件"))
        threading.Thread(target=self.load_data, daemon=True).start()

    def load_data(self):
        try:
            self.df = pd.read_excel(
                self.excel_path,
                engine='openpyxl',
                dtype={'证件号码': str}
            )

            if '证件号码' in self.df.columns:
                self.df['证件号码'] = self.df['证件号码'].astype(str).str.strip()
                self.df.set_index('证件号码', inplace=True, drop=False)

            if '检查记录登记' not in self.df.columns:
                self.df['检查记录登记'] = pd.NA

                self.wb = load_workbook(self.excel_path)
                self.ws = self.wb.active

                for idx, cell in enumerate(self.ws[1]):
                    if cell.value == "证件号码":
                        self.id_column_idx = idx

                new_col = self.ws.max_column + 1
                self.ws.cell(row=1, column=new_col, value="检查记录登记")
                self.record_column_idx = new_col - 1
                self.wb.save(self.excel_path)
                self.message_queue.put(("log", "系统操作", "已添加'检查记录登记'列"))
            else:
                self.wb = load_workbook(self.excel_path)
                self.ws = self.wb.active

                for idx, cell in enumerate(self.ws[1]):
                    if cell.value == "证件号码":
                        self.id_column_idx = idx
                    elif cell.value == "检查记录登记":
                        self.record_column_idx = idx

            self.data_loaded = True
            msg = f"数据加载完成 | 共 {len(self.df)} 条记录"
            self.message_queue.put(("status", msg))
            self.message_queue.put(("log", "系统操作", msg))
        except Exception as e:
            error_msg = f"加载数据失败: {str(e)}"
            self.message_queue.put(("error", error_msg))
            self.message_queue.put(("status", error_msg))
            self.message_queue.put(("log", "系统错误", error_msg))

            try:
                self.try_repair_excel()
            except Exception as repair_error:
                self.message_queue.put(("log", "系统错误", f"尝试修复Excel文件失败: {str(repair_error)}"))

    def try_repair_excel(self):
        try:
            temp_df = pd.read_excel(self.excel_path, engine='xlrd')
            new_path = os.path.splitext(self.excel_path)[0] + "_repaired.xlsx"
            temp_df.to_excel(new_path, index=False)
            self.excel_path = new_path
            self.message_queue.put(("log", "系统操作", f"已修复并保存文件为: {new_path}"))
            self.load_data()
        except Exception as e:
            raise Exception(f"无法修复Excel文件: {str(e)}")

    def clear_search(self):
        self.search_entry.delete(0, tk.END)
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.config(state=tk.DISABLED)
        self.status_var.set("已清空搜索条件")
        self.write_log("用户操作", "清空搜索条件")
        self.current_id = ""
        self.follow_up_btn.config(state=tk.DISABLED, style='primary.TButton')

    def search_id(self):
        if not self.data_loaded:
            self.message_queue.put(("info", "警告", "数据尚未加载完成，请稍后再试"))
            return

        id_number = self.search_entry.get().strip()
        if not id_number:
            self.message_queue.put(("error", "请输入身份证号"))
            return

        if not self.is_valid_id_number(id_number):
            error_msg = "无效的身份证号格式"
            self.message_queue.put(("error", error_msg))
            self.write_log("查询错误", id_number[:6] + "..." + id_number[-4:], error_msg)
            return

        self.status_var.set(f"正在查询: {id_number[:6]}...{id_number[-4:]}")
        self.root.update_idletasks()

        try:
            self.result_text.config(state=tk.NORMAL)
            self.result_text.delete(1.0, tk.END)

            if id_number in self.df.index:
                self.current_id = id_number
                result = self.df.loc[[id_number]]

                follow_up_record = result.iloc[0]["检查记录登记"]
                has_follow_up = not pd.isna(follow_up_record) and str(follow_up_record).strip() != ""

                # 修改按钮状态和样式
                if has_follow_up:
                    self.follow_up_btn.config(state=tk.NORMAL, style='danger.TButton')
                else:
                    self.follow_up_btn.config(state=tk.NORMAL, style='primary.TButton')

                # 获取第一列的名称和值
                first_column_name = self.df.columns[0]
                first_column_value = str(result.iloc[0][first_column_name])

                # 显示第一列内容作为第一行（使用header样式）
                self.result_text.insert(tk.END, f"{first_column_value}\n", 'header')

                # 显示其他列信息（跳过第一列和空值）
                for col_name, value in result.iloc[0].items():
                    if col_name == first_column_name or pd.isna(value) or str(value).strip() == "":
                        continue
                    self.result_text.insert(tk.END, f"{col_name}: {value}\n")

                self.result_text.see(tk.END)

                log_data = " | ".join(
                    [str(x) if pd.notna(x) and str(x).strip() != "" else "" for x in result.iloc[0].values])
                success_msg = f"查询结果: {log_data}"
                self.status_var.set("查询成功")
                self.write_log("查询成功", id_number[:6] + "..." + id_number[-4:], success_msg)
            else:
                not_found_msg = "未找到匹配记录"
                self.result_text.insert(tk.END, not_found_msg + "\n")
                self.status_var.set(f"未找到身份证号: {id_number[:6]}...{id_number[-4:]}")
                self.message_queue.put(("info", "结果", not_found_msg))
                self.write_log("查询结果", id_number[:6] + "..." + id_number[-4:], not_found_msg)
                self.current_id = ""
                self.follow_up_btn.config(state=tk.DISABLED, style='primary.TButton')

            self.result_text.config(state=tk.DISABLED)

        except Exception as e:
            error_msg = f"查询失败: {str(e)}"
            self.message_queue.put(("error", error_msg))
            self.status_var.set(f"查询出错: {str(e)}")
            self.write_log("查询错误", id_number[:6] + "..." + id_number[-4:], error_msg)
            self.current_id = ""
            self.follow_up_btn.config(state=tk.DISABLED, style='primary.TButton')


if __name__ == "__main__":
    root = tk.Tk()
    app = IDSearchApp(root)
    root.mainloop()